using System;
using Microsoft.SPOT;
using System.Threading;

namespace Utilities.Threading
{
    internal class SingleThreadPool
    {
        internal delegate void WaitCallback(object state);
        internal delegate void UnhandledThreadExceptionDelegate(object state, Exception ex);

        public event UnhandledThreadExceptionDelegate UnhandledThreadPoolException;

        Thread _thread;

        WaitCallback _callback;
        object _callBackArgument;
        object _callbackAndArgumentLocker = new object();

        AutoResetEvent _waitEvent = new AutoResetEvent(false);

        public SingleThreadPool(ThreadPriority priority = ThreadPriority.Normal)
        {
            _thread = new Thread(threadProc) {Priority = priority};

            _thread.Start();
        }

        void threadProc()
        {
            while (true)
            {
                _waitEvent.WaitOne();

                lock (_callbackAndArgumentLocker)
                {
                    try
                    {
                        if (_callback != null)
                        {
                            _callback(_callBackArgument);
                            _callback = null;
                        }
                    }
                    catch (Exception ex)
                    {
                        if (UnhandledThreadPoolException != null) UnhandledThreadPoolException(_callBackArgument, ex);
                    }
                }
            }
        }

        public void QueueUserWorkItem(WaitCallback callback, object state = null)
        {
            lock (_callbackAndArgumentLocker)
            {
                _callback = callback;
                _callBackArgument = state;

                _waitEvent.Set();
            }
        }
    }
}
